package com.dwj.auto.comment.common.security.config;

import com.dwj.auto.comment.common.security.*;
import com.dwj.auto.comment.common.security.filter.AuthenticationFilter;
import com.dwj.auto.comment.common.security.filter.UserAuthenticationProcessingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;
    @Autowired
    private UserLoginSuccessHandler userLoginSuccessHandler;
    @Autowired
    private UserLoginFailureHandler userLoginFailureHandler;
    @Autowired
    private UserLogoutSuccessHandler userLogoutSuccessHandler;
    @Autowired
    private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
    @Autowired
    private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;
    @Autowired
    private UserAuthenticationManager userAuthenticationManager;
    @Autowired
    private UserAuthenticationProcessingFilter userAuthenticationProcessingFilter;
    @Autowired
    private AuthenticationFilter authenticationFilter;
    @Autowired
    private UserPermissionEvaluator userPermissionEvaluator;


    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return this.userAuthenticationManager;
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests()//认证请求
                .antMatchers(securityProperties.getIgnorePaths()).permitAll()//忽略的请求
                .anyRequest().authenticated()//其余所有的请求都需要认证
                .and().headers().frameOptions().disable()//允许iframe嵌套
                .and().exceptionHandling().authenticationEntryPoint(userAuthenticationEntryPointHandler)//未登录请求处理
                .accessDeniedHandler(userAuthAccessDeniedHandler)//无权限访问处理类 (此配置可以忽略，全局异常会先于Security框架处理异常，全局异常已特殊处理)
                .and().formLogin().loginPage(securityProperties.getLoginPage()).permitAll()//自定义登录页面并忽略认证
                .loginProcessingUrl(securityProperties.getAuthApi())//指定认证接口
                .successHandler(userLoginSuccessHandler)//登录成功处理器
                .failureHandler(userLoginFailureHandler)//登录失败处理器
                .and().logout().logoutSuccessHandler(userLogoutSuccessHandler)//登出成功处理器
                .logoutSuccessUrl(securityProperties.getLoginPage())//登出成功页面
                .and().cors().and().csrf().disable();//允许跨域
        //自定义过滤器在登录时认证用户名、密码
        httpSecurity.addFilterAt(userAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(authenticationFilter, BasicAuthenticationFilter.class);
        //不创建session会话
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        //取消头缓存控制
        httpSecurity.headers().cacheControl();
    }

    @Bean
    public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(userPermissionEvaluator);
        return handler;
    }

}